1
2
3
4 package joeq.Interpreter;
5
6 import java.util.Arrays;
7 import java.util.HashSet;
8 import java.util.Iterator;
9 import java.util.Set;
10 import joeq.Allocator.ObjectLayout;
11 import joeq.Class.PrimordialClassLoader;
12 import joeq.Class.jq_Array;
13 import joeq.Class.jq_Class;
14 import joeq.Class.jq_InstanceField;
15 import joeq.Class.jq_Method;
16 import joeq.Class.jq_Primitive;
17 import joeq.Class.jq_Reference;
18 import joeq.Class.jq_StaticField;
19 import joeq.Class.jq_StaticMethod;
20 import joeq.Class.jq_Type;
21 import joeq.Main.TraceFlags;
22 import joeq.Main.jq;
23 import joeq.Memory.Address;
24 import joeq.Memory.HeapAddress;
25 import joeq.Memory.StackAddress;
26 import joeq.Runtime.Monitor;
27 import joeq.Runtime.Reflection;
28 import joeq.Runtime.SystemInterface;
29 import joeq.Runtime.TypeCheck;
30 import joeq.Runtime.Unsafe;
31 import joeq.UTF.Utf8;
32 import jwutil.collections.Filter;
33 import jwutil.util.Assert;
34 import jwutil.util.Convert;
35
36 /***
37 * DirectInterpreter
38 *
39 * @author John Whaley <jwhaley@alum.mit.edu>
40 * @version $Id: DirectInterpreter.java 1985 2004-10-08 08:43:02Z joewhaley $
41 */
42 public class DirectInterpreter extends BytecodeInterpreter {
43
44 /*** Creates new DirectInterpreter */
45 public DirectInterpreter(State initialState) {
46 super(new DirectVMInterface(), initialState);
47 }
48
49 public static final Set bad_classes;
50 public static final Set bad_methods;
51 public static final Filter interpret_filter;
52 static {
53 bad_classes = new HashSet();
54 bad_classes.add(SystemInterface._class);
55 bad_classes.add(Reflection._class);
56 bad_classes.add(PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Runtime/ExceptionDeliverer;"));
57 bad_methods = new HashSet();
58 bad_methods.add(joeq.Runtime.Arrays._multinewarray);
59 interpret_filter = new Filter() {
60 public boolean isElement(Object o) {
61 jq_Method m = (jq_Method)o;
62 if (m.getBytecode() == null) return false;
63 if (bad_classes.contains(m.getDeclaringClass())) return false;
64 if (bad_methods.contains(m)) return false;
65 return true;
66 }
67 };
68 }
69
70 public Object invokeMethod(jq_Method m) throws Throwable {
71
72 jq_Class k = m.getDeclaringClass();
73 k.cls_initialize();
74 if (!interpret_filter.isElement(m)) {
75
76 Object result = invokeMethod(m, null);
77
78 return result;
79 }
80 int localsize = m.getMaxLocals() * HeapAddress.size();
81 int stacksize = m.getMaxStack() * HeapAddress.size();
82 StackAddress newframe = StackAddress.alloca(localsize+stacksize);
83 DirectState callee = new DirectState((StackAddress) newframe.offset(localsize+stacksize), (StackAddress) newframe.offset(stacksize), m.getMaxLocals());
84 Object result = this.invokeMethod(m, callee);
85
86 return result;
87 }
88
89
90 public Object invokeMethod(jq_Method m, State callee) throws Throwable {
91
92 jq_Class k = m.getDeclaringClass();
93 Assert._assert(k.isClsInitialized());
94 Assert._assert(m.getBytecode() != null);
95 jq_Type[] paramTypes = m.getParamTypes();
96 Object[] params = new Object[paramTypes.length];
97 for (int i=paramTypes.length-1; i>=0; --i) {
98 jq_Type t = paramTypes[i];
99 if (t.isPrimitiveType()) {
100 if (t == jq_Primitive.LONG) {
101 params[i] = new Long(istate.pop_L());
102 } else if (t == jq_Primitive.FLOAT) {
103 params[i] = new Float(istate.pop_F());
104 } else if (t == jq_Primitive.DOUBLE) {
105 params[i] = new Double(istate.pop_D());
106 } else {
107 params[i] = new Integer(istate.pop_I());
108 }
109 } else {
110 params[i] = istate.pop_A();
111 }
112
113 }
114 for (int i=0, j=0; i<paramTypes.length; ++i, ++j) {
115 jq_Type t = paramTypes[i];
116 if (t.isPrimitiveType()) {
117 if (t == jq_Primitive.LONG) {
118 long v = ((Long)params[i]).longValue();
119 if (callee == null) {
120 Unsafe.pushArg((int)(v>>32));
121 Unsafe.pushArg((int)v);
122 } else callee.setLocal_L(j, v);
123 ++j;
124 } else if (t == jq_Primitive.FLOAT) {
125 float v = ((Float)params[i]).floatValue();
126 if (callee == null) {
127 Unsafe.pushArg(Float.floatToRawIntBits(v));
128 } else callee.setLocal_F(j, v);
129 } else if (t == jq_Primitive.DOUBLE) {
130 long v = Double.doubleToRawLongBits(((Double)params[i]).doubleValue());
131 if (callee == null) {
132 Unsafe.pushArg((int)(v>>32));
133 Unsafe.pushArg((int)v);
134 } else callee.setLocal_D(j, Double.longBitsToDouble(v));
135 ++j;
136 } else {
137 int v = ((Integer)params[i]).intValue();
138 if (callee == null) {
139 Unsafe.pushArg(v);
140 } else callee.setLocal_I(j, v);
141 }
142 } else {
143 Object v = params[i];
144 if (callee == null) {
145 Unsafe.pushArgA(HeapAddress.addressOf(v));
146 } else callee.setLocal_A(j, v);
147 }
148 }
149 if (callee == null) {
150 jq_Type returnType = m.getReturnType();
151 if (returnType.isReferenceType()) {
152 Address result = Unsafe.invokeA(m.getDefaultCompiledVersion().getEntrypoint());
153 if (returnType.isAddressType()) return result;
154 return ((HeapAddress) result).asObject();
155 }
156 long result = Unsafe.invoke(m.getDefaultCompiledVersion().getEntrypoint());
157 if (returnType == jq_Primitive.VOID)
158 return null;
159 else if (returnType == jq_Primitive.LONG)
160 return new Long(result);
161 else if (returnType == jq_Primitive.FLOAT)
162 return new Float(Float.intBitsToFloat((int)(result)));
163 else if (returnType == jq_Primitive.DOUBLE)
164 return new Double(Double.longBitsToDouble(result));
165 else
166 return new Integer((int)(result));
167 } else {
168 State oldState = this.istate;
169 this.istate = callee;
170 MethodInterpreter mi = new MethodInterpreter(m);
171 Object synchobj = null;
172 try {
173 if (m.isSynchronized()) {
174 if (!m.isStatic()) {
175 if (mi.getTraceFlag()) mi.getTraceOut().println("synchronized instance method, locking 'this' object");
176 vm.monitorenter(synchobj = istate.getLocal_A(0), mi);
177 } else {
178 if (mi.getTraceFlag()) mi.getTraceOut().println("synchronized static method, locking class object");
179 vm.monitorenter(synchobj = Reflection.getJDKType(m.getDeclaringClass()), mi);
180 }
181 }
182 mi.forwardTraversal();
183 this.istate = oldState;
184 if (m.isSynchronized()) {
185 if (mi.getTraceFlag()) mi.getTraceOut().println("exiting synchronized method, unlocking object");
186 vm.monitorexit(synchobj);
187 }
188 jq_Type returnType = m.getReturnType();
189 Object retval;
190 if (returnType.isReferenceType()) {
191 retval = callee.getReturnVal_A();
192 } else if (returnType == jq_Primitive.VOID) {
193 retval = null;
194 } else if (returnType == jq_Primitive.LONG) {
195 retval = new Long(callee.getReturnVal_L());
196 } else if (returnType == jq_Primitive.FLOAT) {
197 retval = new Float(callee.getReturnVal_F());
198 } else if (returnType == jq_Primitive.DOUBLE) {
199 retval = new Double(callee.getReturnVal_D());
200 } else {
201 retval = new Integer(callee.getReturnVal_I());
202 }
203 if (mi.getTraceFlag())
204 mi.getTraceOut().println("Return value: "+retval);
205 return retval;
206 } catch (WrappedException ix) {
207 this.istate = oldState;
208 if (m.isSynchronized()) {
209 if (mi.getTraceFlag()) mi.getTraceOut().println("exiting synchronized method, unlocking object");
210 vm.monitorexit(synchobj);
211 }
212 throw ix.t;
213 }
214 }
215 }
216
217 public Object invokeUnsafeMethod(jq_Method f) throws Throwable {
218 if (f == Unsafe._intBitsToFloat) {
219 return new Float(istate.pop_F());
220 } else if (f == Unsafe._floatToIntBits) {
221 return new Integer(istate.pop_I());
222 } else if (f == Unsafe._doubleToLongBits) {
223 return new Long(istate.pop_L());
224 } else if (f == Unsafe._longBitsToDouble) {
225 return new Double(istate.pop_D());
226 } else if (f == Unsafe._getThreadBlock) {
227 return Unsafe.getThreadBlock();
228 } else if (f.getName() == Utf8.get("to32BitValue")) {
229 return new Integer(((Address) istate.pop()).to32BitValue());
230 } else if (f.getName() == Utf8.get("addressOf")) {
231 return HeapAddress.addressOf(istate.pop_A());
232 } else if (f.getName() == Utf8.get("asObject")) {
233 return ((HeapAddress)istate.pop()).asObject();
234 } else if (f.getName() == Utf8.get("offset")) {
235 int i = istate.pop_I();
236 return ((Address)istate.pop()).offset(i);
237 } else if (f.getName() == Utf8.get("asReferenceType")) {
238 return (jq_Reference) ((HeapAddress)istate.pop()).asObject();
239 } else if (f.getName() == Utf8.get("peek")) {
240 return ((Address)istate.pop()).peek();
241 } else if (f.getName() == Utf8.get("peek1")) {
242 return new Integer(((Address)istate.pop()).peek1());
243 } else if (f.getName() == Utf8.get("peek2")) {
244 return new Integer(((Address)istate.pop()).peek2());
245 } else if (f.getName() == Utf8.get("peek4")) {
246 return new Integer(((Address)istate.pop()).peek4());
247 } else if (f.getName() == Utf8.get("peek8")) {
248 return new Long(((Address)istate.pop()).peek8());
249 } else if (f.getName() == Utf8.get("poke")) {
250 Address v = (Address) istate.pop();
251 Address a = (Address) istate.pop();
252 a.poke(v);
253 return null;
254 } else if (f.getName() == Utf8.get("poke1")) {
255 byte v = (byte) istate.pop_I();
256 Address a = (Address) istate.pop();
257 a.poke1(v);
258 return null;
259 } else if (f.getName() == Utf8.get("poke2")) {
260 short v = (short) istate.pop_I();
261 Address a = (Address) istate.pop();
262 a.poke2(v);
263 return null;
264 } else if (f.getName() == Utf8.get("poke4")) {
265 int v = istate.pop_I();
266 Address a = (Address) istate.pop();
267 a.poke4(v);
268 return null;
269 } else if (f.getName() == Utf8.get("poke8")) {
270 long v = istate.pop_L();
271 Address a = (Address) istate.pop();
272 a.poke8(v);
273 return null;
274 } else {
275 System.err.println(f.toString());
276 Assert.UNREACHABLE();
277 return null;
278 }
279 }
280
281 public static class DirectState extends BytecodeInterpreter.State {
282 final StackAddress fp;
283 final int nlocals;
284 StackAddress sp;
285 int loResult, hiResult;
286
287 public DirectState(StackAddress fp, StackAddress sp, int nlocals) {
288 this.fp = fp; this.sp = sp;
289 this.nlocals = nlocals;
290 }
291
292 public void fillInParameters(jq_Type[] paramTypes, Object[] incomingArgs) {
293 for (int i=0, j=0; i<paramTypes.length; ++i, ++j) {
294 jq_Type t = paramTypes[i];
295 if (t.isReferenceType()) {
296 push_A(incomingArgs[j]);
297 } else if (t.isIntLike()) {
298 push_I(Convert.unwrapToInt(incomingArgs[j]));
299 } else if (t == jq_Primitive.FLOAT) {
300 push_F(Convert.unwrapToFloat(incomingArgs[j]));
301 } else if (t == jq_Primitive.LONG) {
302 push_L(Convert.unwrapToLong(incomingArgs[j]));
303 ++j;
304 } else if (t == jq_Primitive.DOUBLE) {
305 push_D(Convert.unwrapToDouble(incomingArgs[j]));
306 ++j;
307 } else {
308 Assert.UNREACHABLE();
309 }
310 }
311 }
312
313 public void push_I(int v) {
314 sp = (StackAddress) sp.offset(-HeapAddress.size());
315 sp.poke4(v);
316 }
317 public void push_L(long v) {
318 push_I((int)(v>>32)); push_I((int)v);
319 }
320 public void push_F(float v) {
321 push_I(Float.floatToRawIntBits(v));
322 }
323 public void push_D(double v) {
324 push_L(Double.doubleToRawLongBits(v));
325 }
326 public void push_A(Object v) {
327 push_R(HeapAddress.addressOf(v));
328 }
329 public void push_R(Address v) {
330 sp = (StackAddress) sp.offset(-HeapAddress.size());
331 sp.poke(v);
332 }
333 public void push(Object v) {
334 push_A(v);
335 }
336 public int pop_I() {
337 int v = sp.peek4();
338 sp = (StackAddress) sp.offset(HeapAddress.size());
339 return v;
340 }
341 public long pop_L() {
342 int lo=pop_I(); int hi=pop_I();
343 return Convert.twoIntsToLong(lo, hi);
344 }
345 public float pop_F() {
346 return Float.intBitsToFloat(pop_I());
347 }
348 public double pop_D() {
349 return Double.longBitsToDouble(pop_L());
350 }
351 public Object pop_A() {
352 return ((HeapAddress) pop_R()).asObject();
353 }
354 public Address pop_R() {
355 Address v = sp.peek();
356 sp = (StackAddress) sp.offset(HeapAddress.size());
357 return v;
358 }
359 public Object pop() {
360 return pop_A();
361 }
362 public void popAll() {
363 sp = (StackAddress) fp.offset(-(nlocals * HeapAddress.size()));
364 }
365 public Object peek_A(int depth) {
366 HeapAddress v = (HeapAddress) sp.offset(depth * HeapAddress.size()).peek();
367 return v.asObject();
368 }
369 public void setLocal_I(int i, int v) {
370 fp.offset(-(i * HeapAddress.size())).poke4(v);
371 }
372 public void setLocal_L(int i, long v) {
373 setLocal_I(i, (int)(v>>32)); setLocal_I(i+1, (int)v);
374 }
375 public void setLocal_F(int i, float v) {
376 setLocal_I(i, Float.floatToRawIntBits(v));
377 }
378 public void setLocal_D(int i, double v) {
379 setLocal_L(i, Double.doubleToRawLongBits(v));
380 }
381 public void setLocal_A(int i, Object v) {
382 setLocal_R(i, HeapAddress.addressOf(v));
383 }
384 public void setLocal_R(int i, Address v) {
385 fp.offset(-(i * HeapAddress.size())).poke(v);
386 }
387 public int getLocal_I(int i) {
388 return fp.offset(-(i * HeapAddress.size())).peek4();
389 }
390 public long getLocal_L(int i) {
391 int lo=getLocal_I(i+1); int hi=getLocal_I(i);
392 return Convert.twoIntsToLong(lo, hi);
393 }
394 public float getLocal_F(int i) {
395 return Float.intBitsToFloat(getLocal_I(i));
396 }
397 public double getLocal_D(int i) {
398 return Double.longBitsToDouble(getLocal_L(i));
399 }
400 public Object getLocal_A(int i) {
401 return ((HeapAddress) getLocal_R(i)).asObject();
402 }
403 public Address getLocal_R(int i) {
404 return fp.offset(-(i * HeapAddress.size())).peek();
405 }
406 public void return_I(int v) {
407 loResult = v;
408 }
409 public void return_L(long v) {
410 loResult = (int)(v>>32); hiResult = (int)v;
411 }
412 public void return_F(float v) {
413 loResult = Float.floatToRawIntBits(v);
414 }
415 public void return_D(double v) {
416 return_L(Double.doubleToRawLongBits(v));
417 }
418 public void return_A(Object v) {
419 loResult = HeapAddress.addressOf(v).to32BitValue();
420 }
421 public void return_V() {}
422 public int getReturnVal_I() {
423 return loResult;
424 }
425 public long getReturnVal_L() {
426 return Convert.twoIntsToLong(loResult, hiResult);
427 }
428 public float getReturnVal_F() {
429 return Float.intBitsToFloat(loResult);
430 }
431 public double getReturnVal_D() {
432 return Double.longBitsToDouble(getReturnVal_L());
433 }
434 public Object getReturnVal_A() {
435 return ((HeapAddress) getReturnVal_R()).asObject();
436 }
437 public Address getReturnVal_R() {
438 return HeapAddress.address32(loResult);
439 }
440 }
441
442 public static class DirectVMInterface extends BytecodeInterpreter.VMInterface {
443 public int getstatic_I(jq_StaticField f) { return f.getAddress().peek4(); }
444 public long getstatic_L(jq_StaticField f) { return f.getAddress().peek8(); }
445 public float getstatic_F(jq_StaticField f) { return Float.intBitsToFloat(getstatic_I(f)); }
446 public double getstatic_D(jq_StaticField f) { return Double.longBitsToDouble(getstatic_L(f)); }
447 public Object getstatic_A(jq_StaticField f) { return ((HeapAddress) f.getAddress().peek()).asObject(); }
448 public byte getstatic_B(jq_StaticField f) { return (byte)f.getAddress().peek4(); }
449 public char getstatic_C(jq_StaticField f) { return (char)f.getAddress().peek4(); }
450 public short getstatic_S(jq_StaticField f) { return (short)f.getAddress().peek4(); }
451 public boolean getstatic_Z(jq_StaticField f) { return f.getAddress().peek4()!=0; }
452 public void putstatic_I(jq_StaticField f, int v) { f.getDeclaringClass().setStaticData(f, v); }
453 public void putstatic_L(jq_StaticField f, long v) { f.getDeclaringClass().setStaticData(f, v); }
454 public void putstatic_F(jq_StaticField f, float v) { f.getDeclaringClass().setStaticData(f, v); }
455 public void putstatic_D(jq_StaticField f, double v) { f.getDeclaringClass().setStaticData(f, v); }
456 public void putstatic_A(jq_StaticField f, Object v) { f.getDeclaringClass().setStaticData(f, v); }
457 public void putstatic_Z(jq_StaticField f, boolean v) { f.getDeclaringClass().setStaticData(f, v?1:0); }
458 public void putstatic_B(jq_StaticField f, byte v) { f.getDeclaringClass().setStaticData(f, v); }
459 public void putstatic_C(jq_StaticField f, char v) { f.getDeclaringClass().setStaticData(f, v); }
460 public void putstatic_S(jq_StaticField f, short v) { f.getDeclaringClass().setStaticData(f, v); }
461 public int getfield_I(Object o, jq_InstanceField f) { return HeapAddress.addressOf(o).offset(f.getOffset()).peek4(); }
462 public long getfield_L(Object o, jq_InstanceField f) { return HeapAddress.addressOf(o).offset(f.getOffset()).peek8(); }
463 public float getfield_F(Object o, jq_InstanceField f) { return Float.intBitsToFloat(getfield_I(o, f)); }
464 public double getfield_D(Object o, jq_InstanceField f) { return Double.longBitsToDouble(getfield_L(o, f)); }
465 public Object getfield_A(Object o, jq_InstanceField f) { return ((HeapAddress)HeapAddress.addressOf(o).offset(f.getOffset()).peek()).asObject(); }
466 public byte getfield_B(Object o, jq_InstanceField f) { return HeapAddress.addressOf(o).offset(f.getOffset()).peek1(); }
467 public char getfield_C(Object o, jq_InstanceField f) { return (char)HeapAddress.addressOf(o).offset(f.getOffset()).peek4(); }
468 public short getfield_S(Object o, jq_InstanceField f) { return (short)HeapAddress.addressOf(o).offset(f.getOffset()).peek2(); }
469 public boolean getfield_Z(Object o, jq_InstanceField f) { return HeapAddress.addressOf(o).offset(f.getOffset()).peek1() != (byte)0; }
470 public void putfield_I(Object o, jq_InstanceField f, int v) { HeapAddress.addressOf(o).offset(f.getOffset()).poke4(v); }
471 public void putfield_L(Object o, jq_InstanceField f, long v) { HeapAddress.addressOf(o).offset(f.getOffset()).poke8(v); }
472 public void putfield_F(Object o, jq_InstanceField f, float v) { putfield_I(o, f, Float.floatToRawIntBits(v)); }
473 public void putfield_D(Object o, jq_InstanceField f, double v) { putfield_L(o, f, Double.doubleToRawLongBits(v)); }
474 public void putfield_A(Object o, jq_InstanceField f, Object v) { HeapAddress.addressOf(o).offset(f.getOffset()).poke(HeapAddress.addressOf(v)); }
475 public void putfield_B(Object o, jq_InstanceField f, byte v) { HeapAddress.addressOf(o).offset(f.getOffset()).poke1(v); }
476 public void putfield_C(Object o, jq_InstanceField f, char v) { HeapAddress.addressOf(o).offset(f.getOffset()).poke2((short)((v<<16)>>16)); }
477 public void putfield_S(Object o, jq_InstanceField f, short v) { HeapAddress.addressOf(o).offset(f.getOffset()).poke2(v); }
478 public void putfield_Z(Object o, jq_InstanceField f, boolean v) { HeapAddress.addressOf(o).offset(f.getOffset()).poke1(v?(byte)1:(byte)0); }
479 public Object new_obj(jq_Type t) { return ((jq_Class)t).newInstance(); }
480 public Object new_array(jq_Type t, int length) { return ((jq_Array)t).newInstance(length); }
481 public Object checkcast(Object o, jq_Type t) {
482 if (t.isAddressType()) return o;
483 return TypeCheck.checkcast(o, t);
484 }
485 public boolean instance_of(Object o, jq_Type t) { return TypeCheck.instance_of(o, t); }
486 public int arraylength(Object o) { return HeapAddress.addressOf(o).offset(ObjectLayout.ARRAY_LENGTH_OFFSET).peek4(); }
487 public void monitorenter(Object o, MethodInterpreter v) { Monitor.monitorenter(o); }
488 public void monitorexit(Object o) { Monitor.monitorexit(o); }
489 public Object multinewarray(int[] dims, jq_Type t) { return joeq.Runtime.Arrays.multinewarray_helper(dims, 0, (jq_Array)t); }
490 public jq_Reference getJQTypeOf(Object o) { return jq_Reference.getTypeOf(o); }
491 }
492
493
494 public static void main(String[] s_args) throws Throwable {
495 String s = s_args[0];
496 int dotloc = s.lastIndexOf('.');
497 String rootMethodClassName = s.substring(0, dotloc);
498 String rootMethodName = s.substring(dotloc+1);
499
500 Assert._assert(jq.RunningNative);
501
502 jq_Class c = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("L"+rootMethodClassName.replace('.','/')+";");
503 c.cls_initialize();
504
505 jq_StaticMethod rootm = null;
506 Utf8 rootm_name = Utf8.get(rootMethodName);
507 for(Iterator it = Arrays.asList(c.getDeclaredStaticMethods()).iterator();
508 it.hasNext(); ) {
509 jq_StaticMethod m = (jq_StaticMethod)it.next();
510 if (m.getName() == rootm_name) {
511 rootm = m;
512 break;
513 }
514 }
515 if (rootm == null)
516 Assert.UNREACHABLE("root method not found: "+rootMethodClassName+"."+rootMethodName);
517 Object[] args = new Object[rootm.getParamWords()];
518 jq_Type[] paramTypes = rootm.getParamTypes();
519 for (int i=0, j=0; i<paramTypes.length; ++i) {
520 j = TraceFlags.parseArg(args, i, paramTypes[i], s_args, j);
521 }
522 StackAddress newframe = StackAddress.alloca(args.length * HeapAddress.size());
523 StackAddress fp = (StackAddress) newframe.offset(args.length * HeapAddress.size());
524 StackAddress sp = fp;
525 DirectState initialState = new DirectState(fp, sp, 0);
526 initialState.fillInParameters(paramTypes, args);
527 Object retval = new DirectInterpreter(initialState).invokeMethod(rootm);
528 System.out.println("Return value: "+retval);
529 }
530
531 }